
#################################################################
### 利用xgboost对菠菜公司赔率进行预测
#################################################################
import os
import numpy as np
import pandas as pd
import xgboost as xgb
from xgboost import XGBClassifier


companys = ['Bet365', 'WilliamHill', 'Ladbrokes', 'Bet_at_home', 'Vcbet', 'Easybets',
              'Interwetten', '_10BET', '_12bet', '_18Bet', 'Bwin', 'Crown', 'Betfair']

### 三分类
xgboost_model_3class = r'./Data/model/xgboost_model_3class(10.16).json'
### 二分类
xgboost_model_2class = r'./Data/model/xgboost_model_2class(8.26).json'

class odds_prediction():

    def load_data(self, loadfile=r'./prediction/datasets/today_matchs_company_odds.csv'):
        matchs = pd.read_csv(loadfile, encoding="gbk",header=None, names = ['league', 'season', 'bs_num_id', 'bs_time', 'hometeam', 'awayteam',
                        'Bet365_s1', 'Bet365_sX', 'Bet365_s2', 'Bet365_e1', 'Bet365_eX', 'Bet365_e2',
                        'WilliamHill_s1', 'WilliamHill_sX', 'WilliamHill_s2', 'WilliamHill_e1', 'WilliamHill_eX', 'WilliamHill_e2',
                        'Ladbrokes_s1', 'Ladbrokes_sX', 'Ladbrokes_s2', 'Ladbrokes_e1', 'Ladbrokes_eX', 'Ladbrokes_e2',
                        'Bet_at_home_s1', 'Bet_at_home_sX', 'Bet_at_home_s2', 'Bet_at_home_e1', 'Bet_at_home_eX', 'Bet_at_home_e2',
                        'Vcbet_s1', 'Vcbet_sX', 'Vcbet_s2', 'Vcbet_e1', 'Vcbet_eX', 'Vcbet_e2',
                        'Easybets_s1', 'Easybets_sX', 'Easybets_s2', 'Easybets_e1', 'Easybets_eX', 'Easybets_e2',
                        'Interwetten_s1', 'Interwetten_sX', 'Interwetten_s2', 'Interwetten_e1', 'Interwetten_eX', 'Interwetten_e2',
                        '_10BET_s1', '_10BET_sX', '_10BET_s2', '_10BET_e1', '_10BET_eX', '_10BET_e2',
                        '_12bet_s1', '_12bet_sX', '_12bet_s2', '_12bet_e1', '_12bet_eX', '_12bet_e2',
                        '_18Bet_s1', '_18Bet_sX', '_18Bet_s2', '_18Bet_e1', '_18Bet_eX', '_18Bet_e2',
                        'Bwin_s1', 'Bwin_sX', 'Bwin_s2', 'Bwin_e1', 'Bwin_eX', 'Bwin_e2',
                        'Crown_s1', 'Crown_sX', 'Crown_s2', 'Crown_e1', 'Crown_eX', 'Crown_e2',
                        'Betfair_s1', 'Betfair_sX', 'Betfair_s2', 'Betfair_e1', 'Betfair_eX', 'Betfair_e2'])

        matchs.sort_values(by='bs_time', axis=0, ascending=True, inplace=True)
        matchs = matchs.reset_index(drop=True)

        return matchs

    def odds_to_probability(self, matchs):
        prob_matchs = pd.DataFrame()
        for n in range(len(companys)):
            odds_start = matchs[[companys[n]+'_s1', companys[n]+'_sX', companys[n]+'_s2']]
            odds_end = matchs[[companys[n] + '_e1', companys[n] + '_eX', companys[n] + '_e2']]

            QI_start = 1 / odds_start[companys[n]+'_s1'] + 1 / odds_start[companys[n]+'_sX'] + 1 / odds_start[companys[n]+'_s2']
            return_percentage0 = 1 / QI_start

            QI_end = 1 / odds_end[companys[n]+'_e1'] + 1 / odds_end[companys[n]+'_eX'] + 1 / odds_end[companys[n]+'_e2']
            return_percentage9 = 1 / QI_end

            prob_matchs['prob_'+companys[n]+'_s1'] = return_percentage0 / odds_start[companys[n]+'_s1']  # kelly_home
            prob_matchs['prob_'+companys[n]+'_sX'] = return_percentage0 / odds_start[companys[n]+'_sX']  # kelly_draw
            prob_matchs['prob_'+companys[n]+'_s2'] = return_percentage0 / odds_start[companys[n]+'_s2']  # kelly_away

            prob_matchs['prob_'+companys[n]+'_e1'] = return_percentage9 / odds_end[companys[n]+'_e1']  # kelly_home
            prob_matchs['prob_'+companys[n]+'_eX'] = return_percentage9 / odds_end[companys[n]+'_eX']  # kelly_draw
            prob_matchs['prob_'+companys[n]+'_e2'] = return_percentage9 / odds_end[companys[n]+'_e2']  # kelly_away

        prob_matchs = pd.concat([matchs, prob_matchs], axis=1)

        return prob_matchs

    def get_features(self, matchs):
        prob_s1 = pd.DataFrame()
        prob_sX = pd.DataFrame()
        prob_s2 = pd.DataFrame()
        prob_e1 = pd.DataFrame()
        prob_eX = pd.DataFrame()
        prob_e2 = pd.DataFrame()
        prob_s = pd.DataFrame()
        prob_e = pd.DataFrame()
        for n in range(0, len(companys)):
            prob_s1 = pd.concat([prob_s1, matchs[['prob_'+companys[n]+'_s1']]], axis=1)
            prob_sX = pd.concat([prob_sX, matchs[['prob_'+companys[n]+'_sX']]], axis=1)
            prob_s2 = pd.concat([prob_s2, matchs[['prob_'+companys[n]+'_s2']]], axis=1)
            prob_e1 = pd.concat([prob_e1, matchs[['prob_'+companys[n]+'_e1']]], axis=1)
            prob_eX = pd.concat([prob_eX, matchs[['prob_'+companys[n]+'_eX']]], axis=1)
            prob_e2 = pd.concat([prob_e2, matchs[['prob_'+companys[n]+'_e2']]], axis=1)

            prob_s = pd.concat([prob_s, matchs[['prob_'+companys[n]+'_s1', 'prob_'+companys[n]+'_sX', 'prob_'+companys[n]+'_s2']]], axis=1)
            prob_e = pd.concat([prob_e, matchs[['prob_'+companys[n]+'_e1', 'prob_'+companys[n]+'_eX', 'prob_'+companys[n]+'_e2']]], axis=1)

        mean_s1 = prob_s1.mean(axis=1)
        mean_sX = prob_sX.mean(axis=1)
        mean_s2 = prob_s2.mean(axis=1)
        mean_e1 = prob_e1.mean(axis=1)
        mean_eX = prob_eX.mean(axis=1)
        mean_e2 = prob_e2.mean(axis=1)

        std_s1 = prob_s1.std(axis=1)
        std_sX = prob_sX.std(axis=1)
        std_s2 = prob_s2.std(axis=1)
        std_e1 = prob_e1.std(axis=1)
        std_eX = prob_eX.std(axis=1)
        std_e2 = prob_e2.std(axis=1)

        prob_dv = 100 * (prob_e.values - prob_s.values) / prob_s.values
        features = pd.DataFrame(prob_dv)
        # features[(-2<features) & (features<2)] = 0
        # features[features>=2] = 1
        # features[features<=-2] = -1

        features['mean_s1_e1'] = mean_e1 - mean_s1
        features['mean_sX_eX'] = mean_eX - mean_sX
        features['mean_s2_e2'] = mean_e2 - mean_s2

        features['std_s1_e1'] = std_e1 - std_s1
        features['std_sX_eX'] = std_eX - std_sX
        features['std_s2_e2'] = std_e2 - std_s2

        # features[(-0.01<features[['mean_s1_e1','mean_sX_eX','mean_s2_e2']]) & (features[['mean_s1_e1','mean_sX_eX','mean_s2_e2']]<0.01)] = 0
        # features[features[['mean_s1_e1','mean_sX_eX','mean_s2_e2']]>=0.01] = 1
        # features[features[['mean_s1_e1','mean_sX_eX','mean_s2_e2']]<=-0.01] = -1

        features['mean_s1'] = mean_s1
        features['mean_sX'] = mean_sX
        features['mean_s2'] = mean_s2
        features['mean_e1'] = mean_e1
        features['mean_eX'] = mean_eX
        features['mean_e2'] = mean_e2
        # features['std_s1'] = std_s1
        # features['std_sX'] = std_sX
        # features['std_s2'] = std_s2
        features['std_e1'] = std_e1
        features['std_eX'] = std_eX
        features['std_e2'] = std_e2

        return features


    def predict_3class(self, matchs, features):
        model = xgb.Booster()
        model.load_model(xgboost_model_3class)
        # model.load_model('D:\qiutan_predict\Data\model\\xgboost_model(2).json')

        matchs_mat = xgb.DMatrix(features)
        pred_proba = model.predict(matchs_mat)
        pred = np.argmax(pred_proba, axis=1)
        pred = pd.DataFrame(pred, columns=['pred_3class'])

        pred[pred == 0] = "主胜"
        pred[pred == 1] = "平局"
        pred[pred == 2] = "客胜"
        pred_result = pd.concat([pd.DataFrame(np.around(pred_proba, 4), columns=['pred_home_3', 'pred_draw_3', 'pred_away_3']), pred], axis=1)
        # pred_result = pred_result[['pred_home_3', 'pred_draw_3', 'pred_away_3','predict']]

        companys_odds = matchs[[companys[0] + '_e1', companys[0] + '_eX', companys[0] + '_e2']]
        companys_odds = companys_odds.values
        for n in range(1, len(companys)):
            odds_end = matchs[[companys[n] + '_e1', companys[n] + '_eX', companys[n] + '_e2']]
            odds_end = odds_end.values
            companys_odds = companys_odds + odds_end

        mean_odds = companys_odds / len(companys)
        QI = (1 / mean_odds[:, :1]) + (1 / mean_odds[:, 1:2]) + (1 / mean_odds[:, 2:3])
        return_percentage = 1 / QI
        prob_company = return_percentage / mean_odds

        mean_odds = np.around(mean_odds, 2)
        prob_company = np.around(prob_company, 3)
        mean_odds = pd.DataFrame(mean_odds, columns=['home_odd', 'draw_odd', 'away_odd'])
        prob_company = pd.DataFrame(prob_company, columns=['home_prob', 'draw_prob', 'away_prob'])

        pred_result = pd.concat([matchs[['league', 'bs_time', 'hometeam', 'awayteam']], mean_odds, prob_company, pred_result], axis=1)

        return pred_result


    def predict_2class(self, matchs, features):
        model = xgb.Booster()
        model.load_model(xgboost_model_2class)

        clf = XGBClassifier()
        clf._Booster = model
        pred_proba = clf.predict_proba(features)
        pred = np.argmax(pred_proba, axis=1)
        pred = pd.DataFrame(pred, columns=['pred_2class'])
        pred[pred == 0] = "正路"
        pred[pred == 1] = "反路"
        pred_result = pd.DataFrame(pred_proba, columns=['forward', 'reverse'])
        pred_result = pred_result.round(3)

        conditions =[(matchs['Bet365_eX'] > (matchs['Bet365_e1'] * 1.1)) & (matchs['Bet365_eX'] > (matchs['Bet365_e2'] * 1.1)),
                    (matchs['Bet365_e1'] < (matchs['Bet365_eX'] * 0.9)) & (matchs['Bet365_e1'] < (matchs['Bet365_e2'] * 0.9)),
                     (matchs['Bet365_e2'] < (matchs['Bet365_eX'] * 0.9)) & (matchs['Bet365_e2'] < (matchs['Bet365_e1'] * 0.9))]
        values = ['平局', '主胜', '客胜']
        pred_result['book_ward'] = np.select(conditions, values)

        pred_result = pd.concat([pred_result, pred], axis=1)

        return pred_result


def df_insert(df, n, arr, ignore_index=True):
	"""
	DataFrame任意位置添加一行
	:param df: DataFrame
	:param n: 添加行号索引
	:param arr: 添加数据
	:param ignore_index: 是否无视行索引，为True则重新从0生成df的行号
	:return: DataFrame
	"""
	# 如果原df列名被修改，则需要给新插入的行也赋予列名
	# arr = pd.DataFrame（np.array(arr).reshape((1, len(arr))）, columns=df.columns)
	# 否则直接插入二维数组即可
	arr = [arr]
	df1 = df[:n]
	df2 = df[n:]
	df0 = df1.append(arr, ignore_index).append(df2, ignore_index)
	return df0





def xgb_odds_predict():
    pred = odds_prediction()
    matchs = pred.load_data()
    prob_matchs = pred.odds_to_probability(matchs)
    features = pred.get_features(prob_matchs)

    pred_result2 = pred.predict_2class(prob_matchs, features)
    pred_result3 = pred.predict_3class(prob_matchs, features)

    pred_result = pd.concat([pred_result3, pred_result2], axis=1)
    # pred_result = pred_result3

    # condition = [(pred_result.pred_3class == "主胜") & (pred_result.prob_Bet365_e1 <= (pred_result.pred_home_3 + 0.08)),
    #              (pred_result.pred_3class == "平局") & (pred_result.prob_Bet365_eX <= (pred_result.pred_draw_3 + 0.03)),
    #              ((pred_result.pred_3class == "客胜") & (pred_result.prob_Bet365_e2 <= pred_result.pred_away_3))]

    condition = [(pred_result.pred_3class == "主胜") & ((pred_result.home_prob + 0.03) <= pred_result.pred_home_3),
                 (pred_result.pred_3class == "平局"),
                 ((pred_result.pred_3class == "客胜") & ((pred_result.away_prob + 0.02) <= pred_result.pred_away_3))]
    values = ['价投-主', '价投-平局', '价投-客']

    pred_result['valueBet'] = np.select(condition, values)

    # nowtime = time.strftime('%Y%m%d_%H_%M', time.localtime())
    # result_file = "./prediction/datasets/xbs_odds_predResult{}.csv".format(nowtime)

    # nowtime = time.strftime('%Y%m%d', time.localtime())
    result_file = r"./prediction/datasets/xbs_odds_predResult.csv"

    if (os.path.exists(result_file)):
        matchs = pd.read_csv(result_file, encoding="utf-8")
        for i in range(len(pred_result)):
            bs_num_id = pred_result.iloc[i]["bs_num_id"]
            ids = matchs.loc[:, "bs_num_id"]
            is_exists = False
            for j in range(len(ids)-1, -1, -1):
                if bs_num_id == ids.iloc[j]:
                    df1 = matchs[:(j+1)]
                    df2 = matchs[(j+1):]
                    df3 = pred_result[i:i+1]
                    matchs = pd.concat([df1, df3, df2], axis=0)
                    is_exists = True
                    break
            if not is_exists:
                matchs = pd.concat([matchs, pd.DataFrame(pred_result.iloc[i]).T], axis=0, ignore_index=True)
        matchs.to_csv(result_file, encoding="utf-8", index=None)
    else:
        pred_result.to_csv(result_file, encoding="utf-8", index=None)









